from treeKernel import ftree
from classDef import *
from typing import Dict
import warnings
warnings.filterwarnings("ignore", category=DeprecationWarning)

class crudUser:
    """
    前端或affine后端，都可能调用其中的部分接口
    """
    _last_write_time:float=0
    def __init__(self, tree: ftree):
        self.tree = tree
        self.session=self.tree.session
        self.err = ErrorCode(self.session)
    @rollback_on_exception
    @trace_info()
    def addUser(self, user: str) -> Dict[str, Union[str,int]]:
        """
        添加用户（仅需要 user）
        """
        i_dict: Dict[str, Union[str,int]]={"success":1,"message":"success"}
        if self.tree.root().permission.get(user, -1) == -1:
            self.tree.addUser(user)
            # self.tree.r
        else:
            i_dict["message"]=f"user {user} already exists with permission {self.tree.root().permission.get(user, 0):08b}"
        i_dict["success"]=self.tree.root().permission.get(user, -1)
        return self.err.IF_SUCCESS_COMMIT(i_dict)
    @rollback_on_exception
    @trace_info()
    def delUser(self, user: str) -> Dict[str, Union[str,int]]:
        """
        删除用户,agent不会自发删除用户,所以python端命令行删除用户后不会发信息给affine后端同步。
        所有节点的权限列表中,pop掉user
        但不会导致空间/文件的删除（只会在affine主动调用下删除）
        """
        return self.tree.delUser(user)
    @rollback_on_exception
    @trace_info()
    def createDoc(self, user: str, a_spaceId: str, a_docId: str, newDocName: str) -> Dict[str, Union[str,int]]:
        """
        创建一个文档，若成功返回 success，否则返回错误信息
        """
        SpaceMap = (
            self.session.query(affmap)
            .where(affmap.a_spaceId == a_spaceId, affmap.a_docId == "")# type: ignore
            .first()
        )  
        if SpaceMap is None:
            return self.err.MAPFRAME_NOT_FOUND("SpaceMap")
        i_docId_Dict = self.tree.addNode(user, SpaceMap.intId, newDocName, "doc", by="user")
        i_docId = int(i_docId_Dict.get("success", -1))
        if i_docId < 0:
            return i_docId_Dict
        docMap = affmap(a_docId=a_docId, a_spaceId=a_spaceId, intId=i_docId)
        self.session.add(docMap)
        return self.err.IF_SUCCESS_COMMIT(i_docId_Dict)
    @rollback_on_exception
    @trace_info()
    def createSpace(self, user: str, a_spaceId: str, newSpaceName: str) -> Dict[str, Union[str,int]]:
        """
        创建一个空间（目录），若成功返回 success，否则返回错误信息
        """
        i_spaceId_Dict = self.tree.addNode(user, self.tree.root(), newSpaceName, "space", by="user")
        i_spaceId = int(i_spaceId_Dict.get("success", -1))
        if i_spaceId < 0:
            return i_spaceId_Dict
        spaceMap = affmap(a_docId="", a_spaceId=a_spaceId, intId=i_spaceId)  # type: ignore
        self.session.add(spaceMap)
        return self.err.IF_SUCCESS_COMMIT(i_spaceId_Dict)
    @rollback_on_exception
    @trace_info()
    def renameDoc(self, user: str, a_spaceId: str, a_docId: str, newDocName: str) -> Dict[str, Union[str,int]]:
        """
        重命名文档.注意a_docId不会变，只是文件节点的名字变。
        """
        DocMap = (
            self.session.query(affmap)
            .where(affmap.a_spaceId == a_spaceId, affmap.a_docId == a_docId) # type: ignore
            .first()
        ) 
        if DocMap is None:
            return self.err.MAPFRAME_NOT_FOUND("DocMap")
        i_docId_Dict = self.tree.renameNode(user, DocMap.intId, newDocName, by="user")
        return self.err.IF_SUCCESS_COMMIT(i_docId_Dict)
    @rollback_on_exception
    @trace_info()
    def renameSpace(self, user: str, a_spaceId: str, newSpaceName: str) -> Dict[str, Union[str,int]]:
        """
        重命名空间（目录）
        """
        SpaceMap = (
            self.session.query(affmap)
            .where(affmap.a_spaceId == a_spaceId, affmap.a_docId == "") # type: ignore
            .first()
        ) 
        if SpaceMap is None:
            return self.err.MAPFRAME_NOT_FOUND("SpaceMap")
        i_spaceId_Dict = self.tree.renameNode(user, SpaceMap.intId, newSpaceName, by="user")
        return self.err.IF_SUCCESS_COMMIT(i_spaceId_Dict)
    @rollback_on_exception
    @trace_info()
    def deleteDoc(self, user: str, a_spaceId: str, a_docId: str) -> Dict[str, Union[str,int]]:
        """
        删除文档
        """
        DocMap = (
            self.session.query(affmap)
            .where(affmap.a_spaceId == a_spaceId, affmap.a_docId == a_docId)# type: ignore
            .first()
        )  
        if DocMap is None:
            return self.err.MAPFRAME_NOT_FOUND("DocMap")
        i_docId_Dict = self.tree.deleteNode(user, DocMap.intId, by="user")
        return self.err.IF_SUCCESS_COMMIT(i_docId_Dict)
    @rollback_on_exception
    @trace_info()
    def deleteSpace(self, user: str, a_spaceId: str) -> Dict[str, Union[str,int]]:
        """
        删除空间（目录）
        """
        SpaceMap = (
            self.session.query(affmap)
            .where(affmap.a_spaceId == a_spaceId, affmap.a_docId == "")# type: ignore
            .first()
        )  
        if SpaceMap is None:
            return self.err.MAPFRAME_NOT_FOUND("SpaceMap")
        i_spaceId_Dict = self.tree.deleteNode(user, SpaceMap.intId, by="user")
        return self.err.IF_SUCCESS_COMMIT(i_spaceId_Dict)
    @rollback_on_exception
    @trace_info()
    def writeDoc(self, user: str, a_spaceId: str, a_docId: str, content: str) -> Dict[str, Union[str,int]]:
        """
        往文档中写入内容
        """
        DocMap = (
            self.session.query(affmap)
            .where(affmap.a_spaceId == a_spaceId, affmap.a_docId == a_docId) # type: ignore
            .first()
        )
        if DocMap is None:
            return self.err.MAPFRAME_NOT_FOUND("DocMap")
        i_docId_Dict = self.tree.buildMdTree(user, DocMap.intId, content, by="user")
        return self.err.IF_SUCCESS_COMMIT(i_docId_Dict)

    @rollback_on_exception
    @trace_info()
    def moveDoc(self, user: str, a_spaceId: str, a_docId: str, dest_a_spaceId: str, dest_a_docId: str) -> Dict[str, Union[str,int]]:
        """
        移动文档到另一个空间.由于affine后端移动后的文档有个新的affid，所以需要记录到dest_docMap
        """
        DocMap = (
            self.session.query(affmap)
            .where(affmap.a_spaceId == a_spaceId, affmap.a_docId == a_docId)# type: ignore
            .first()
        )
        DestSpaceMap = (
            self.session.query(affmap)
            .where(affmap.a_spaceId == dest_a_spaceId, affmap.a_docId == "")# type: ignore
            .first()
        )  
        if DestSpaceMap is None:
            return self.err.MAPFRAME_NOT_FOUND("DestSpaceMap")
        if DocMap is None:
            return self.err.MAPFRAME_NOT_FOUND("DocMap")
        i_docId_Dict = self.tree.moveNode(user, DocMap.intId, DestSpaceMap.intId, by="user")
        dest_docMap = affmap(a_docId=dest_a_docId, a_spaceId=dest_a_spaceId, intId=DocMap.intId)
        self.session.add(dest_docMap)
        self.session.delete(DocMap)
        return self.err.IF_SUCCESS_COMMIT(i_docId_Dict)
    @rollback_on_exception
    @trace_info()
    def copyDoc(self, user: str, a_spaceId: str, a_docId: str, dest_a_spaceId: str, dest_a_docId: str) -> Dict[str, Union[str,int]]:
        """
        复制文档到另一个空间.由于affine后端复制后的文档有个新的affid，所以需要记录到dest_docMap
        """
        DocMap = (
            self.session.query(affmap)
            .where(affmap.a_spaceId == a_spaceId, affmap.a_docId == a_docId)# type: ignore
            .first()
        )  
        DestSpaceMap = (
            self.session.query(affmap)
            .where(affmap.a_spaceId == dest_a_spaceId, affmap.a_docId == "")# type: ignore
            .first()
        )  
        if DestSpaceMap is None:
            return self.err.MAPFRAME_NOT_FOUND("DestSpaceMap")
        if DocMap is None:
            return self.err.MAPFRAME_NOT_FOUND("DocMap")
        dest_i_docId_Dict = self.tree.copyNode(user, DocMap.intId, DestSpaceMap.intId, by="user")
        dest_i_docId = int(dest_i_docId_Dict.get("success", -1))
        if dest_i_docId < 0:
            return dest_i_docId_Dict
        dest_docMap = affmap(a_docId=dest_a_docId, a_spaceId=dest_a_spaceId, intId=dest_i_docId)
        self.session.add(dest_docMap)
        return self.err.IF_SUCCESS_COMMIT(dest_i_docId_Dict)
    def agentPerm(self, user:str, a_spaceId: str,a_docId:str, permChar:str, method:str) -> Dict[str,Union[str,int]]:
        """
        设置 Agent 的权限。由前端调用.如果a_docId是空就只找到空间
        """
        DocSpaceMap = (
            self.session.query(affmap)
            .where(affmap.a_spaceId == a_spaceId, affmap.a_docId == a_docId)# type: ignore
            .first()
        )  
        if DocSpaceMap is None:
            return self.err.MAPFRAME_NOT_FOUND(f"agentPerm a_spaceId={a_spaceId}, a_docId={a_docId}")
        i_Dict=self.tree.agentPerm(user, DocSpaceMap.intId, permChar, method)
        return self.err.IF_SUCCESS_COMMIT(i_Dict)
    def share(self, user: str, a_spaceId: str, a_docId: str,  permChar: str ,share_user: str,) -> Dict[str, Union[str,int]]:
        """
        分享文件或空间给其他用户，支持分享一个文件夹或一个文件.
        """
        DocSpaceMap = (
            self.session.query(affmap)
            .where(affmap.a_spaceId == a_spaceId, affmap.a_docId == a_docId)  # type: ignore
            .first()
        )
        if DocSpaceMap is None:
            return self.err.MAPFRAME_NOT_FOUND(f"share a_spaceId={a_spaceId}, a_docId={a_docId}")
        return self.tree.shareNode(user, DocSpaceMap.intId,  permChar,share_user)  # type: ignore
    def literalSearch(self, user:str, query:str,ensure_full_return_type:str="",affSpaceId:str="",useRegex:bool=False)->Dict[str, Union[str,int]]:
        """
        字面量搜索。由前端调用
        """
        if affSpaceId=="":
            subRoot=1
        else:
            spaceMap=self.session.query(affmap).where(affmap.a_spaceId==affSpaceId,affmap.a_docId=="").first()#type: ignore
            if spaceMap is None:
                return self.err.MAPFRAME_NOT_FOUND("spaceMap")
            subRoot=spaceMap.intId
        if useRegex:
            regOption="regex" 
        else:
            regOption="literal"
        treestr=self.tree.RAG(user,query,ensure_full_return_type,regOption,"user","ja",subRoot)
        return {"success":1,"content":treestr,"message":"success"}
    def semanticSearch(self, user:str, query:str,ensure_full_return_type:str="",affSpaceId:str="")->Dict[str, Union[str,int]]:
        """
        语义搜索。由前端调用
        """
        if affSpaceId=="":
            subRoot=1
        else:
            spaceMap=self.session.query(affmap).where(affmap.a_spaceId==affSpaceId,affmap.a_docId=="").first()#type: ignore
            if spaceMap is None:
                return self.err.MAPFRAME_NOT_FOUND("spaceMap")
            subRoot=spaceMap.intId
        treestr=self.tree.RAG(user,query,ensure_full_return_type,"semantic","user","ja",subRoot)
        return {"success":1,"content":treestr,"message":"success"}
    


if __name__=="__main__":
    tree = ftree()
    crud = crudUser(tree)
    
    print(crud.addUser("user1"))
    print(crud.createSpace("user1", "a_space1", "space1"))
    print(crud.createSpace("user1", "a_space2", "space2"))
    print(crud.createDoc("user1", "a_space1", "a_doc1", "doc1"))
    print(crud.renameDoc("user1", "a_space1", "a_doc1", "doc2"))
    print(crud.renameSpace("user1", "a_space1", "space3"))
    # print(crud.deleteDoc("user1", "a_space1", "a_doc1"))
    # print(crud.deleteSpace("user1", "a_space1"))
    print(crud.writeDoc("user1", "a_space1", "a_doc1", "# content for space1 doc1\n## h2 title\n- list item 1\n- list item 2\n\n[link text](https://example.com)"))
    print(crud.moveDoc("user1", "a_space1", "a_doc1", "a_space2", "a_doc2"))
    
